#include "pch.hpp"
#include "D3D11RasterizerState.hpp"
#include "D3D11Exception.hpp"

using namespace Engine;
using namespace Engine::Video;




D3D11RasterizerState::D3D11RasterizerState(const notify& destroyedFn)
	: m_destroyed(destroyedFn)
	, m_changed(false)

	, m_fillmode(Fillmode::solid)
	, m_cullmode(Cullmode::back)
	, m_frontCounterClockwise(false)
	, m_depthBias(0)
	, m_depthBiasClamp(0.0)
	, m_slopeScaledDepthBias(0.0)
	, m_depthClipping(true)
	, m_scissorClipping(false)
{}
///////////////////////////////////////////////////////////////////////////////////////////////////

void D3D11RasterizerState::post_create(ptr _this)
{
	m_this = _this;
}
///////////////////////////////////////////////////////////////////////////////////////////////////

D3D11RasterizerState::~D3D11RasterizerState()
{
	m_destroyed(m_this);
}
///////////////////////////////////////////////////////////////////////////////////////////////////




void D3D11RasterizerState::setFillmode(Fillmode::Type mode)
{
	m_fillmode = mode;
	m_changed = true;
}
///////////////////////////////////////////////////////////////////////////////////////////////////

void D3D11RasterizerState::setCullmode(Cullmode::Type mode)
{
	m_cullmode = mode;
	m_changed = true;
}
///////////////////////////////////////////////////////////////////////////////////////////////////

void D3D11RasterizerState::setDepthclipping(bool enabled)
{
	m_depthClipping = enabled;
	m_changed = true;
}
///////////////////////////////////////////////////////////////////////////////////////////////////




const ID3D11RasterizerStatePtr& D3D11RasterizerState::apply(const ID3D11DevicePtr& device, D3D11DeviceContext& context)
{
	update(device, context);

	return m_rasterizerState;
}
///////////////////////////////////////////////////////////////////////////////////////////////////

void D3D11RasterizerState::update(const ID3D11DevicePtr& device, D3D11DeviceContext& context)
{
	if(!m_changed)
		return;

	D3D11_RASTERIZER_DESC desc;
	ZeroMemory(&desc, sizeof(desc));
	desc.CullMode              = cullMode(m_cullmode);
	desc.FillMode              = fillMode(m_fillmode);
	desc.FrontCounterClockwise = m_frontCounterClockwise;
	desc.DepthBias             = m_depthBias;
	desc.DepthBiasClamp        = m_depthBias;
	desc.SlopeScaledDepthBias  = m_slopeScaledDepthBias;
	desc.DepthClipEnable       = m_depthClipping;
	desc.ScissorEnable         = m_scissorClipping;
	desc.MultisampleEnable     = false;
	desc.AntialiasedLineEnable = false;

	ID3D11RasterizerState* state;
	D3D11_API(device->CreateRasterizerState(&desc, &state));
	m_rasterizerState = ID3D11RasterizerStatePtr(state);

	m_changed = false;
}
///////////////////////////////////////////////////////////////////////////////////////////////////

D3D11_FILL_MODE D3D11RasterizerState::fillMode(Fillmode::Type type)
{
	switch(type)
	{
	case Fillmode::wireframe: return D3D11_FILL_WIREFRAME;
	case Fillmode::solid:     return D3D11_FILL_SOLID;
	default: BOOSTEXT_THROW(invalid_value_exception(type));
	}
}
///////////////////////////////////////////////////////////////////////////////////////////////////

D3D11_CULL_MODE D3D11RasterizerState::cullMode(Cullmode::Type type)
{
	switch(type)
	{
	case Cullmode::none: return D3D11_CULL_NONE;
	case Cullmode::front:  return D3D11_CULL_FRONT;
	case Cullmode::back: return D3D11_CULL_BACK;
	default: BOOSTEXT_THROW(invalid_value_exception(type));
	}
}
///////////////////////////////////////////////////////////////////////////////////////////////////
